-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: 410 Report Verification - LFO #2714
Conversation
1c5ce43
to
26f888f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work!! I've left a few comments, mostly small stuff.
I think there's some RJSF features that we can use to cut down on the schema/data manipulation, ideally we're writing code where only the form drives the data, and the components only needs to (hopefully not too much) transform it before submitting it to the API
constraints = [ | ||
models.CheckConstraint( | ||
name="other_facility_must_have_coordinates", | ||
check=~Q(is_other_visit=True) | Q(visit_coordinates__isnull=False), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to exclude the case "is_other_visit=True and visit_coordinates__isnull=True"
check=~(Q(is_other_visit=True) & Q(visit_coordinates__isnull=True))
verification_body_name: str = Field(...) | ||
accredited_by: str = Field(...) | ||
scope_of_verification: str = Field(...) | ||
threats_to_independence: bool = Field(...) | ||
verification_conclusion: str = Field(...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are redundant with the fields = ...
in the Meta class, we can just delete these lines
visit_name: str = Field(...) | ||
visit_type: str = Field(choices=ReportVerificationVisit.VisitType.choices) | ||
is_other_visit: bool = Field(...) | ||
visit_coordinates: str = Field(required=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, I think the choices and required options will be inferred from the model if we just remove these lines
report_verification_visits: List[ReportVerificationVisitSchema] = Field(default_factory=list) | ||
|
||
class Meta(BaseReportVerification.Meta): | ||
fields = BaseReportVerification.Meta.fields + ['report_version'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all these schemas we could actually generate them dynamically, since they're just a subset of the fields on the model: https://django-ninja.dev/guides/response/django-pydantic-create-schema/
@@ -13,17 +15,19 @@ class ReportVerificationService: | |||
@staticmethod | |||
def get_report_verification_by_version_id( | |||
report_version_id: int, | |||
) -> ReportVerification: | |||
) -> ReportVerificationOut: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should consider decoupling the service layer from the API layer who owns these data structures. The service layer can declare similar types, or just return the Model types
# Fetch ReportVerificationVisit instances corresponding to the IDs | ||
visit_instances_to_keep = ReportVerificationVisit.objects.filter(id__in=visit_ids_to_keep) | ||
|
||
# Update report_verification_visits | ||
report_verification.report_verification_visits.set(visit_instances_to_keep) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is necessary, all the ReportVerificationVisit
models have been created with the right report_verification
field set, and this is not an m2m relationship.
We can remove these few lines
# Create related ReportVerificationVisit instances and link them | ||
report_verification_visits = baker.make_recipe( | ||
"reporting.tests.utils.report_verification_visit", | ||
_quantity=2, | ||
) | ||
|
||
# Attach the visits to the report_verification instance | ||
self.report_verification.report_verification_visits.set(report_verification_visits) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Create related ReportVerificationVisit instances and link them | |
report_verification_visits = baker.make_recipe( | |
"reporting.tests.utils.report_verification_visit", | |
_quantity=2, | |
) | |
# Attach the visits to the report_verification instance | |
self.report_verification.report_verification_visits.set(report_verification_visits) | |
# Create related ReportVerificationVisit instances and link them | |
report_verification_visits = baker.make_recipe( | |
"reporting.tests.utils.report_verification_visit", | |
report_verification=report_verification, | |
_quantity=2, | |
) |
is_other_visit: true, | ||
visit_coordinates: formData.visit_others.visit_coordinates || "", | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure there is a way to bake this in to the rjsf structure instead, with if then else
or oneOf / anyOf
. Happy to try to pair on that if you want!
bciers/apps/reporting/src/app/components/verification/VerificationForm.tsx
Show resolved
Hide resolved
initialData.visit_types = undefined; | ||
initialData.visit_others = [{}]; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like work that could be done on the server by the API layer (maybe in django ninja schema?): preparing the data for the form and the client page
3040f10
to
8485ae0
Compare
487640d
to
e405d43
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! I'm just leaving a couple of nitpicks, but this is ready to go otherwise :)
visit_name: str | ||
visit_type: Optional[str] = Field(None) | ||
is_other_visit: bool | ||
visit_coordinates: str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are inferred from the django model, they're redundant with the Meta fields = [...]
declaration. We can just remove those lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pbastia
FYI: when I remove the "redundant fields" I get MyPy failed
Mypy.....................................................................Failed
reporting/service/report_verification_service.py:67:31: error: "ReportVerificationVisitSchema" has no attribute "visit_type" [attr-defined]
reporting/service/report_verification_service.py:68:35: error: "ReportVerificationVisitSchema" has no attribute "is_other_visit" [attr-defined]
reporting/service/report_verification_service.py:69:38: error: "ReportVerificationVisitSchema" has no attribute "visit_coordinates" [attr-defined]
reporting/service/report_verification_service.py:74:28: error: "ReportVerificationVisitSchema" has no attribute "visit_name" [attr-defined]
assert len(response_json["report_verification_visits"]) == len(payload.report_verification_visits) | ||
for i, visit_data in enumerate(response_json["report_verification_visits"]): | ||
expected_visit = payload.report_verification_visits[i] | ||
print(expected_visit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
print
left behind
export const createVerificationUiSchema = ( | ||
schemaType: "SFO" | "LFO", | ||
): RJSFSchema => { | ||
// Determine the schema based on the schemaType | ||
const localUiSchema: RJSFSchema = | ||
schemaType === "SFO" ? { ...sfoUiSchema } : { ...lfoUiSchema }; | ||
|
||
// Return the customized schema. | ||
return localUiSchema; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the UiSchemas are only used in this one form, I think we can safely return the object directly
(also, the {...sfoUiSchema} syntax only allows for a shallow copy, so its usefulness is already debatable. This is why we write it as JSON.parse(JSON.stringify(stuff))
sometimes, although this will not work if we have functions in the object values)
export const createVerificationUiSchema = ( | |
schemaType: "SFO" | "LFO", | |
): RJSFSchema => { | |
// Determine the schema based on the schemaType | |
const localUiSchema: RJSFSchema = | |
schemaType === "SFO" ? { ...sfoUiSchema } : { ...lfoUiSchema }; | |
// Return the customized schema. | |
return localUiSchema; | |
}; | |
export const getVerificationUiSchema = ( | |
schemaType: "SFO" | "LFO", | |
): RJSFSchema => { | |
// Determine the schema based on the schemaType | |
const localUiSchema: RJSFSchema = | |
schemaType === "SFO" ? sfoUiSchema : lfoUiSchema; | |
// Return the customized schema. | |
return localUiSchema; | |
}; |
fb25262
to
d6c7c61
Compare
chore: update verification service chore: cleanup chore: cleanup test: verification api get chore: add verification operation type chore: ad shared verification schema properties chore: add verification dependacncies chore: shared schemas chore: refactor SFO updateReportVerificationVisits chore: cleanup chore: cleanup
chore: cleanup chore: cleanup chore: cleanup
chore: cleanup chore: cleanup chore: cleanup chore: cleanup
b18eb7c
to
0e30a94
Compare
chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore: cleanup chore:cleanup chore: cleanup chore: revert
5fa3ca4
to
c39bf13
Compare
Addresses 410
🚀 Impact:
📝 To Dos:
🔬 Local Testing:
Tests SFO "Site(s) Visited" conditional fields*
Bugle SFO - Registered
verification step: http://localhost:3000/reporting/reports/1/verificationSite(s) Visited
= "None"Save & Continue
Expected Results
Attachment
page is displayedBugle SFO - Registered
verification step: http://localhost:3000/reporting/reports/1/verificationExpected Results
Site(s) Visited
= "Other"Save & Continue
Expected Results
Attachment
page is displayedBugle SFO - Registered
verification step: http://localhost:3000/reporting/reports/1/verificationExpected Results
Site(s) Visited
= "Facility 22"Save & Continue
Expected Results
Attachment
page is displayedBugle SFO - Registered
verification step: http://localhost:3000/reporting/reports/1/verificationExpected Results
Tests LFO "Site(s) Visited" conditional fields*
Banana LFO - Registered
verification step: http://localhost:3000/reporting/reports/2/verificationSite(s) Visited
= "None"Save & Continue
Expected Results
Attachment
page is displayedBanana LFO - Registered
verification step: http://localhost:3000/reporting/reports/2/verificationExpected Results
Site(s) Visited
= "Other"Save & Continue
Expected Results
Attachment
page is displayedExpected Results
Site(s) Visited
= "Facility 1"Save & Continue
Expected Results
Attachment
page is displayedBanana LFO - Registered
verification step: http://localhost:3000/reporting/reports/2/verificationExpected Results